package com.gl.order.commom.util;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.gl.order.config.JwtConfig;
import com.gl.order.security.model.SecurityToken;
import com.gl.order.security.model.SecurityUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;

import javax.security.auth.login.AccountException;
import javax.security.auth.login.AccountExpiredException;
import java.security.GeneralSecurityException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * @author liangSY
 * @date 2021/6/7 23:28
 */
@Slf4j
public class JwtTokenUtils {


    public static TimedCache<String, String> timedCache = CacheUtil.newTimedCache(JwtConfig.expirationTime);

    // 创建token
    public static String createToken(SecurityUser user){
        String toketn = Jwts.builder()
                .setId(user.getCurrentUserInfo().getId()) // 用户Id
                .setSubject(user.getCurrentUserInfo().getAccount()) // 主题
                .setIssuedAt(DateTime.now())
                .signWith(SignatureAlgorithm.HS512, JwtConfig.secret) //签名算法，密钥
                .setExpiration(new Date(System.currentTimeMillis()+JwtConfig.expirationTime)) // 设置有效时间
                .compact();
        return toketn;
    }

    // 生成刷新令牌
    public static String createRefreshToken(SecurityUser user){
        String toketn = Jwts.builder()
                .setId(user.getCurrentUserInfo().getId()) // 用户Id
                .setSubject(user.getCurrentUserInfo().getAccount()) // 主题
                .setIssuedAt(DateTime.now())
                .signWith(SignatureAlgorithm.HS512,JwtConfig.secret) //签名算法，密钥
                .setExpiration(new Date(System.currentTimeMillis()+JwtConfig.refreshExpirationTime)) // 设置有效时间
                .compact();
        return toketn;
    }

    /**
     * 解释token
     * @param token
     */
    public static Claims parseToken(String token){
//        token = token.substring(JwtConfig.tokenPrefix.length()+1);
        // 去除请求头的前缀
        try {
            Claims claims = Jwts.parser().setSigningKey(JwtConfig.secret).parseClaimsJws(token).getBody();
            return claims;
        }catch (ExpiredJwtException e){// jwt过期时处理
            return e.getClaims();
        }catch (Exception e){
            log.info(e.getMessage(),e);
            throw new  RuntimeException("token解析失败");
        }
    }


    /**
     *
     * @param token
     * @return
     */
    public static SecurityUser getUserInfo(String token){
        // 去除请求头的前缀
//        token = token.substring(JwtConfig.tokenPrefix.length()+1);
//        Claims claims = parseToken(token);
//        String userId = claims.getId();
        String userJob = timedCache.get(token);
        SecurityUser securityUser = JSONUtil.toBean(userJob,SecurityUser.class);
        return securityUser;
    }




    // 存储jwttoken状态
    public static void saveAccessToken(SecurityToken token, SecurityUser user){
        timedCache.put(token.getAccess_token(),JSONUtil.toJsonStr(user));
        timedCache.put(user.getCurrentUserInfo().getId(),token.getAccess_token());
    }


    /**
     *  移除token状态
     * @param user
     */
    public static void removeToken(SecurityUser user,String token){
        timedCache.remove(token);
        timedCache.remove(user.getCurrentUserInfo().getId());
    }

    /**
     * 检查token是否过期
     */
    public static boolean verifyToken(String token){
        Claims claims = parseToken(token);
        Date expiration = claims.getExpiration();
        LocalDateTime endTime = LocalDateTimeUtil.of(expiration);
        // diff为负数时，则说明过期时间小于当前时间，token已失效
        Long diff = LocalDateTimeUtil.between(LocalDateTimeUtil.now(),endTime,ChronoUnit.MILLIS);
        return diff > 0;
    }

    /**
     * 判断jwt的状态是有效，主要针对注销等操作使用
     * @param key
     * @return true 有效，false：无效
     */
    public static boolean isLoginOfKey(String key){
        if(key.startsWith(JwtConfig.tokenPrefix)){
            key = key.substring(JwtConfig.tokenPrefix.length()+1);
        }
        boolean state = timedCache.containsKey(key);
        return state;
    }



}
